import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

// NOTE TO THE MARKER:
// This implementation treats the start node as though it is not a food node.
// i.e. if we pass through the start node multiple times, we do not get more food.

public class MazeSearch {
	public static void main(String[] args) {
//		// For testing
//		// TODO: Remember to delete before submitting assignment
//		args = new String[2];
//		args[0] = "samplemaze.txt";
//		args[1] = "DFS";
		
		// Decode the arguments
		String fileName = args[0];
		String searchAlgorithm = args[1];
		
		// Construct the maze
		Maze maze = new Maze();
		constructMaze(fileName, maze);
		
		// Initialise the path, treasure hunter and state list
		MazeNodes path = new MazeNodes();
		path.add(maze.getNodes().findNode("Start"));
		TreasureHunter th = new TreasureHunter(path.get(0).getFood_gain());
		StateList sl = new StateList();
		sl.add(new State(maze.getNodes().findNode("Start"), th.getFq()));
		
		// Run the specified search algorithm
		if (searchAlgorithm.equalsIgnoreCase("Backtrack")) {
			if(!Backtracking.backtracking(path,maze,th,sl)){
				System.out.println("ERROR: No path to treasure was found.");
			}
		} else if (searchAlgorithm.equalsIgnoreCase("BFS") || searchAlgorithm.equalsIgnoreCase("DFS") || searchAlgorithm.equalsIgnoreCase("A")) {
			SearchTree.graphSearchForTreasure(searchAlgorithm.toUpperCase(), maze, path);
		} else {
			System.out.println("Invalid search algorithm selected.");
		}
	}
	
	public static void constructMaze(String fileName, Maze maze) {
		BufferedReader inputReader = null;
		try {
			// have a go at opening the file
			inputReader = new BufferedReader(new FileReader(fileName));
		} catch (FileNotFoundException e) {
			System.out.println("File not found: " + fileName);
		}

		// Now the file is opened.
		String line;
		try {
			while ((line = inputReader.readLine()) != null) {
				String[] elements = line.split(" ");
				
				if (elements.length == 2) {
					// this is a maze node
					MazeNode node;
					
					// what kind of maze node is this
					if (elements[0].startsWith("Start")) {
						// this is the start node
						node = new MazeNode(elements[0], MazeNode.Type.START, Integer.parseInt(elements[1]), 0);
						maze.setStartFQ(Integer.parseInt(elements[1]));
						CostedPath.startFQ = maze.getStartFQ();
					} else if (elements[0].startsWith("Food")) {
						// this is a Food node
						node = new MazeNode(elements[0], MazeNode.Type.FOOD, Integer.parseInt(elements[1]), 0);
					} else if (elements[0].startsWith("Pit")) {
						// this is a pit node
						node = new MazeNode(elements[0], MazeNode.Type.PIT, 0, Integer.parseInt(elements[1]));
					} else if (elements[0].startsWith("Treasure")) {
						// this is the treasure node
						node = new MazeNode(elements[0], MazeNode.Type.TREASURE, 0, 0);
					} else if (elements[0].startsWith("Troll")) {
						// this is a Troll node
						node = new MazeNode(elements[0], MazeNode.Type.TROLL, 0, Integer.MAX_VALUE / 2);
					} else {
						// this is a banal node
						node = new MazeNode(elements[0], MazeNode.Type.BANAL, 0, Integer.parseInt(elements[1]));
					}
					
					maze.insertMazeNode(node);
					
				} else if (elements.length == 3) {
					// this is a maze edge
					MazeNode source = maze.findAndCreate(elements[0]);
					MazeNode destination = maze.findAndCreate(elements[1]);
					MazeEdge edge = new MazeEdge(source, destination, Integer.parseInt(elements[2]));
					maze.insertMazeEdge(edge);
				} else {
					// something was wrong
					continue;
				}
			}
		} catch (IOException e) {
			System.out.println("Error reading from file.");
		}
	}
}
